package com.klondike.common.io;

import static com.klondike.common.Constants.UTF_8;
import static com.klondike.common.Utils.checkNull;
import static com.klondike.common.Utils.hasValue;
import static com.klondike.common.Utils.ifNullOrBlank;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;

public class ResourceUtils extends IOUtils {
    public static final String DEFAULT_ENCODING = UTF_8;

    public static Reader getResourceAsReader(Class<?> contextClass, String name) throws IOException {
        return getResourceAsReader(contextClass, name, DEFAULT_ENCODING);
    }

    public static Reader getResourceAsReader(Class<?> contextClass, String name, String enc) throws IOException {
        return getResourceAsReader(contextClass, name, enc, false);
    }

    public static String getResourceAsString(Class<?> contextClass, String name) throws IOException {
        return getResourceAsString(contextClass, name, null);
    }

    public static String getResourceAsString(Class<?> contextClass, String name, String enc) throws IOException {
        Reader reader = getResourceAsReader(contextClass, name, enc);

        return toString(reader);
    }

    public static Reader getResourceAsReader(Class<?> contextClass, String name, String enc, boolean lenient)
            throws IOException {
        InputStream in = contextClass.getResourceAsStream(name);
        if (in == null) {
            if (lenient) {
                return null;
            }
            throw new IOException("no such resource with name " + name);
        }

        return new InputStreamReader(in, ifNullOrBlank(enc, DEFAULT_ENCODING));
    }

    /**
     * @param url
     *            is the URL or file path
     * @return null if not able to load the reader specified by url
     */
    public static Reader getAsReader(String url) throws IOException {
        URL resource = findResource(url);
        Reader reader = null;
        if (resource != null) {
            reader = new InputStreamReader(resource.openStream(), DEFAULT_ENCODING);
        }

        checkNull(reader, String.format("Invalid resource url '%s'", url));

        return reader;
    }

    public static URL findResource(String url) {
        URL resource = null;
        if (hasValue(url)) {
            try {
                resource = new URL(url);
            } catch (MalformedURLException e) {
            }

            if (resource == null) {
                resource = Thread.currentThread().getContextClassLoader().getResource(url);
            }
        }

        return resource;
    }

    public static Properties getConfigurationByUrl(String url) {
        Properties properties = null;
        try {
            Reader reader = getAsReader(url);
            properties = new com.klondike.common.Properties();

            properties.load(reader);

            closeQuietly(reader);
        } catch (IOException e) {
            properties = null;
        }

        return properties;
    }

    /**
     * Return the content of the reader.
     * 
     * @param file
     *            the non-binary file.
     * @return the String content
     */
    public static String getContentAsString(Reader reader) {
        String content = null;
        try {
            StringWriter sw = new StringWriter(1 * 1024);

            copyAndClose(reader, sw);

            content = sw.toString();
        } catch (IOException e) {
            // error occurred
        }

        return content;
    }

    /**
     * Return the content of the file.
     * 
     * @param file
     *            the non-binary file.
     * @return the String content
     */
    public static String getResourceAsString(String url) {
        String content = null;
        try {
            URL resourceURL = findResource(url);
            if (resourceURL != null) {
                InputStream in = resourceURL.openStream();
                InputStreamReader reader = new InputStreamReader(in, DEFAULT_ENCODING);

                content = getContentAsString(reader);
            }

        } catch (IOException e) {
            // error occurred
        }

        return content;
    }

    public static URI toURI(URL url) throws IOException {
        try {
            return url.toURI();
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }
}
